[HNOI2015]亚瑟王

2020-01-19
HNOI

题意

有$n$张牌,每张牌有$p_i$的概率被打出,造成$d_i$的伤害

每回合按顺序考虑每一张牌,若该牌打出就结束该回合

共有$r$轮,求造成的期望伤害

题解

要解决的就是第i张牌前打出牌数量不同,设前i张牌中出了j张的概率为$f_{i,j}$,容易得出f的递推式

分别解决每张牌被打出的概率

统计答案即可

调试记录

循环的范围太小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <cstdio>
#include <cstring>
const int maxn = 255;
using namespace std;
double p[maxn], d[maxn], pow[maxn][maxn], f[maxn][maxn];
int min(int a, int b){
return a < b ? a : b;
}
int T, n, r;
int main(){
scanf("%d", &T);
while (T--){
memset(pow, 0, sizeof pow); memset(f, 0, sizeof f);
scanf("%d%d", &n, &r);
for (int i = 1; i <= n; i++){
scanf("%lf%lf", p + i, d + i);
pow[i][0] = 1;
for (int j = 1; j <= r; j++) pow[i][j] = pow[i][j - 1] * (1 - p[i]);
}
f[0][0] = 1;
for (int i = 1; i <= n; i++){
for (int j = 0; j <= min(i, r); j++){
f[i][j] = f[i - 1][j] * pow[i][r - j];
if (j != 0) f[i][j] += f[i - 1][j - 1] * (1 - pow[i][r - j + 1]);
}
}
double ans = 0;
for (int i = 1; i <= n; i++){
double P = 0;
for (int j = 0; j <= min(i, r); j++)
P += f[i - 1][j] * (1 - pow[i][r - j]);
ans += P * d[i];
}
printf("%.10lf\n", ans);
}
return 0;
}